home *** CD-ROM | disk | FTP | other *** search
- /*
- ** $VER: graphics3Df_i.c 10.10 (16.02.98)
- **
- ** Internal functions for graphics3D.library
- **
- ** (C) Copyright 97 Patrizio Biancalani
- ** All Rights Reserved.
- **
- ** Note: this code is traslate from the blitzbasic 3d graphics engine
- ** V 0.9 of Maciej R. Gorny.
- */
-
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <proto/exec.h>
- #include <proto/intuition.h>
- #include <intuition/intuition.h>
- #include <intuition/screens.h>
-
- #include <graphics/rastport.h>
- #include <graphics/clip.h>
- #include <graphics/regions.h>
- #include <graphics/gfx.h>
- #include <graphics/gfxmacros.h>
- #include <graphics/layers.h>
-
- #include "graphics3Dc.h"
- #include "graphics3D.h"
- #include "graphics3d2d.h"
- #include "graphics3d2d_proto.h"
-
- /** prototipi locali **/
- struct objectnode *resetobj(struct ambient3d *in);
- struct objectnode *nextobj(struct ambient3d *in);
- struct objectnode *pobj(struct ambient3d *in);
-
- /*** funzioni esterne solo matematiche ***/
- extern void matidentity4x4(struct matrix4x4 *imatrix);
- extern void matzero4x4(struct matrix4x4 imatrix);
- extern void matcopy4x4(struct matrix4x4 *s_m,struct matrix4x4 *d_m);
- extern void matmult4x4(struct matrix4x4 *a,struct matrix4x4 *b,
- struct matrix4x4 *r);
- extern void matmult4x4s(struct matrix4x4 *a,struct matrix4x4 *b,
- struct matrix4x4 *r);
- extern void matmult1x4s(struct matrix1x4 *a,struct matrix4x4 *b,
- struct matrix1x4 *r);
- extern void makevector3d(struct vertex *a,struct vertex *b,
- struct vector *result);
- extern long int vectormag3d(struct vector *a);
- extern void normalpol(struct vertex *v0,struct vertex *v1,
- struct vertex *v2,struct vector *normal);
- extern long int dotproduct(struct vector *u,struct vector *v);
- extern long int sqri(long int v);
- extern long int abs(long int val);
-
- /************************************/
- /* costruzione tavole seno e coseno */
- /************************************/
- void buildlookuptables(in)
- struct ambient3d *in;
- {
- long int *sn,*cn,i,ii;
- long int t[]=
- {
- /** val. seno angolo (0,90) e moltiplicato per 256 **/
- 0,4,9,13,17,22,26,30,35,39,43,47,52,
- 56,60,65,69,73,77,81,85,89,93,98,101,105,
- 109,113,117,121,125,129,132,136,140,143,
- 147,151,154,157,161,164,167,171,174,177,
- 180,183,186,189,192,195,198,200,203,206,
- 208,211,213,216,218,220,222,225,227,229,
- 230,232,234,236,238,239,241,242,243,245,
- 246,247,248,249,250,251,252,253,253,254,
- 254,255,255,255,256
- };
-
- /*
- #ifdef DEBUG
- char dbg[80];
- #endif
- */
-
- sn=in->sintable;
- cn=in->costable;
- /** val. seno angolo (0,90) e moltiplicato per 1024 **/
- /*
- t:=[0,17,35,53,71,89,
- 106,124,142,160,177,195,212,230,247,264,282,299,
- 316,333,350,366,383,399,416,432,448,464,480,496,
- 511,527,542,557,572,587,601,615,630,644,657,671,
- 684,698,711,723,736,748,760,772,784,795,806,817,
- 828,838,848,858,868,877,886,895,903,912,920,927,
- 935,942,949,955,962,968,973,979,984,988,993,997,
- 1001,1005,1008,1011,1013,1016,1018,1020,1021,1022,
- 1023,1023,1024]:LONG
- */
- ii=0;
- for(i=0; i<361; i++)
- {
- if (i<91)
- {
- sn[i]=t[ii];
- cn[i]=t[90-ii];
- }
- else if (i<181)
- {
- sn[i]=t[90-ii];
- cn[i]=-t[ii];
- }
- else if (i<271)
- {
- sn[i]=-t[ii];
- cn[i]=-t[90-ii];
- }
- else
- {
- sn[i]=-t[90-ii];
- cn[i]=t[ii];
- }
- /*
- #ifdef DEBUG
- sprintf(dbg,"t[%ld]=%ld sn[%ld]=%ld cn[%ld]=%ld\n",ii,t[ii],i,sn[i],i,cn[i]);
- write_dbg(dbg);
- #endif
- */
- ii++;
- if (ii>90) ii=1;
- }
- }
-
- /*******************************************************/
- /** crea la matrice di trasformazione inversa globale **/
- /** usata per passare da coordinate del mondo in **/
- /** coordinate della camera **/
- /** Crea matrice in.global_view per capirci. **/
- /*******************************************************/
- void createworldtocamera(in)
- struct ambient3d *in;
- {
- long int temp,active_axes;
- struct matrix4x4 translate,rotate_x,rotate_y,rotate_z;
- struct matrix4x4 result_1,result_2,*g_v;
- struct vector *v_p;
- struct dir3d *v_a;
- long int *cos,*sin;
-
- cos=in->costable;
- sin=in->sintable;
- v_a=&in->view_angle;
- v_p=&in->view_point;
- g_v=&in->global_view;
-
- active_axes=0;
-
- matidentity4x4(&translate);
- translate.r3c0=-v_p->x;
- translate.r3c1=-v_p->y;
- translate.r3c2=-v_p->z;
-
- if (v_a->angx!=NULL AND v_a->angx!=360)
- {
- matidentity4x4(&rotate_x);
- rotate_x.r1c1=cos[v_a->angx];
- rotate_x.r1c2=sin[v_a->angx];
- rotate_x.r2c1=-sin[v_a->angx];
- rotate_x.r2c2=cos[v_a->angx];
- active_axes=active_axes+1;
- }
-
- if (v_a->angy!=NULL AND v_a->angy!=360)
- {
- matidentity4x4(&rotate_y);
- rotate_y.r0c0=cos[v_a->angy];
- rotate_y.r0c2=sin[v_a->angy];
- rotate_y.r2c0=-sin[v_a->angy];
- rotate_y.r2c2=cos[v_a->angy];
- active_axes=active_axes+2;
- }
-
- if (v_a->angz!=NULL AND v_a->angz!=360)
- {
- matidentity4x4(&rotate_z);
- rotate_z.r0c0=cos[v_a->angz];
- rotate_z.r0c1=-sin[v_a->angz];
- rotate_z.r1c0=sin[v_a->angz];
- rotate_z.r1c1=cos[v_a->angz];
- active_axes=active_axes+4;
- }
-
- switch (active_axes)
- {
- case (0):
- matcopy4x4(&translate,g_v);
- break;
-
- case (1):
- matcopy4x4(&rotate_x,g_v);
- g_v->r3c0=-v_p->x;
- temp=-v_p->y*cos[v_a->angy] - v_p->z*sin[v_a->angy];
- g_v->r3c1=temp >> SFIXV;
- temp=v_p->y*sin[v_a->angy] - v_p->z*cos[v_a->angy];
- g_v->r3c2=temp >> SFIXV;
- break;
-
- case (2):
- matcopy4x4(&rotate_y,g_v);
- temp=-v_p->x*cos[v_a->angy]+v_p->z*sin[v_a->angy];
- g_v->r3c0=temp >> SFIXV;
- g_v->r3c1=-v_p->y;
- temp=-v_p->y*sin[v_a->angy]-v_p->z*cos[v_a->angy];
- g_v->r3c2=temp >> SFIXV;
- break;
-
- case (3):
- matmult4x4s(&translate,&rotate_x,&result_1);
- matmult4x4s(&result_1,&rotate_y,g_v);
- break;
-
- case (4):
- matcopy4x4(&rotate_z,g_v);
- temp=-v_p->x*cos[v_a->angz]-v_p->y*sin[v_a->angz];
- g_v->r3c0=temp >> SFIXV;
- temp= v_p->x*sin[v_a->angz]-v_p->y*cos[v_a->angz];
- g_v->r3c1=temp >> SFIXV;
- g_v->r3c3=-v_p->z;
- break;
-
- case (5):
- matmult4x4s(&translate,&rotate_x,&result_1);
- matmult4x4s(&result_1,&rotate_z,g_v);
- break;
-
- case (6):
- matmult4x4s(&translate,&rotate_y,&result_1);
- matmult4x4s(&result_1,&rotate_z,g_v);
- break;
-
- case (7):
- matmult4x4s(&translate,&rotate_x,&result_1);
- matmult4x4s(&result_1,&rotate_y,&result_2);
- matmult4x4s(&result_2,&rotate_z,g_v);
-
- }
- }
-
- /*****************************************************/
- /** determina se l'intero oggetto corrente e' fuori **/
- /** dal volume compreso nella visuale o inattivo. **/
- /** Se si rimosso ,ritorna un valore <>0 **/
- /*****************************************************/
- long int t_removeobject(in)
- struct ambient3d *in;
- {
- long int n_z,f_z;
- long int temp,x_bsphere,y_bsphere,z_bsphere;
- long int xmax,ymax,zmax,xmin,ymin,zmin,x_compare,y_compare;
- struct objectnode *obj;
- struct matrix4x4 *g_v;
-
- #ifdef DEBUG
- char dbg[100];
- #endif
-
- /* trasformo da interi a fixpoint */
- f_z=in->far_z * FIXV;
- n_z=in->near_z * FIXV;
-
- obj=pobj(in);
- g_v=&in->global_view;
-
- /* test se oggetto disattivato ,quindi invisibile */
- if (!obj->state) return(1);
-
- /* segnalo oggetto non clippato per default */
- obj->clipped=0;
-
- xmax=obj->xmax;
- ymax=obj->ymax;
- zmax=obj->zmax;
- xmin=obj->xmin;
- ymin=obj->ymin;
- zmin=obj->zmin;
-
- temp=obj->worldposx*g_v->r0c0 + obj->worldposy*g_v->r1c0 +
- obj->worldposz*g_v->r2c0;
- x_bsphere=(temp>>SFIXV) + g_v->r3c0;
- temp=obj->worldposx*g_v->r0c1 + obj->worldposy*g_v->r1c1 +
- obj->worldposz*g_v->r2c1;
- y_bsphere=(temp>>SFIXV) + g_v->r3c1;
- temp=obj->worldposx*g_v->r0c2 + obj->worldposy*g_v->r1c2 +
- obj->worldposz*g_v->r2c2;
- z_bsphere=(temp>>SFIXV) + g_v->r3c2;
-
- /*
- #ifdef DEBUG
- sprintf(dbg,"r0c2=%ld r1c2=%ld r2c2=%ld r3c2=%ld\n",g_v->r0c1,g_v->r1c2,
- g_v->r2c2,g_v->r3c2);
- write_dbg(dbg);
- sprintf(dbg,"temp=%ld x=%ld y=%ld z=%ld\n",temp,obj->worldposx,
- obj->worldposy,obj->worldposz);
- write_dbg(dbg);
- sprintf(dbg,"far=%ld near=%ld zmax=%ld zmin=%ld\n",f_z,n_z,zmax,zmin);
- write_dbg(dbg);
- sprintf(dbg,"xmax=%ld xmin=%ld ymax=%ld ymin=%ld\n",xmax,xmin,ymax,ymin);
- write_dbg(dbg);
- sprintf(dbg,"x=%ld y=%ld z=%ld\n",x_bsphere,y_bsphere,z_bsphere);
- write_dbg(dbg);
- sprintf(dbg,"clipmode ZPLANE\n");
- if (in->clip_mode!=ZPLANE) sprintf(dbg,"clipmode FRUSTUM\n");
- write_dbg(dbg);
- #endif
- */
-
- /* clip con bounding box */
- if (in->clip_mode==ZPLANE)
- {
- if (z_bsphere+zmax>f_z OR z_bsphere+zmin<n_z)
- {
- obj->clipped=1;
- /*
- #ifdef DEBUG
- sprintf(dbg,"oggetto clippato 2\n");
- write_dbg(dbg);
- #endif
- */
- return(2);
- }
- else
- {
- /*
- #ifdef DEBUG
- sprintf(dbg,"oggetto non clippato\n");
- write_dbg(dbg);
- #endif
- */
- return(0);
- }
- }
- else
- {
- /* esegue un completo test su XYZ */
- if ((z_bsphere+zmax)>f_z OR (z_bsphere+zmin)<n_z)
- {
- obj->clipped=1;
- /*
- #ifdef DEBUG
- sprintf(dbg,"oggetto clippato 3\n");
- write_dbg(dbg);
- #endif
- */
- return(3);
- }
- temp=in->half_screen_width*z_bsphere;
- x_compare=temp/in->viewing_distance;
- /*
- #ifdef DEBUG
- sprintf(dbg,"x_comp=%ld\n",x_compare);
- write_dbg(dbg);
- #endif
- */
- if ((x_bsphere+xmax)>x_compare OR (x_bsphere+xmin)<-x_compare)
- {
- obj->clipped=1;
- /*
- #ifdef DEBUG
- sprintf(dbg,"oggetto clippato 4\n");
- write_dbg(dbg);
- #endif
- */
- return(4);
- }
- temp=(in->half_screen_height*z_bsphere)/in->viewing_distance;
- y_compare=(temp*in->inv_aspect_ratio) >> SFIXV;
- /*
- #ifdef DEBUG
- sprintf(dbg,"temp=%ld iv_a_r=%ld y_comp=%ld\n",temp,in->inv_aspect_ratio,
- y_compare);
- write_dbg(dbg);
- #endif
- */
- if ((y_bsphere+ymax)>y_compare OR (y_bsphere+ymin)<-y_compare)
- {
- obj->clipped=1;
- /*
- #ifdef DEBUG
- sprintf(dbg,"oggetto clippato 5\n");
- write_dbg(dbg);
- #endif
- */
- return(5);
- }
- }
- /*
- #ifdef DEBUG
- sprintf(dbg,"oggetto non clippato\n");
- write_dbg(dbg);
- #endif
- */
-
- return(0);
- }
-
- /*******************************************************
- ** trasla le coordinate locali dell'oggetto corrente **
- ** nelle coordinate del mondo **
- *******************************************************
- *** INPUT : *
- * in -> valore > 0 restituito da display3d. *
- *** OUTPUT: *
- * nessuno. *
- *******************************************************/
- void localtoworld(in)
- struct ambient3d *in;
- {
- struct objectnode *obj;
- long int index;
- struct vertex *vg,*vl;
- struct polygon *pl;
- long int wx,wy,wz;
-
- obj=pobj(in);
- vg=obj->vcamera;
- vl=obj->vlocal;
- pl=obj->polys;
- wx=obj->worldposx;
- wy=obj->worldposy;
- wz=obj->worldposz;
-
- for (index=0; index<obj->numverts; index++)
- {
- vg[index].x=vl[index].x+wx;
- vg[index].y=vl[index].y+wy;
- vg[index].z=vl[index].z+wz;
- }
- /* resetta flag di invisibilita' */
- for (index=0; index<obj->numpolys; index++)
- {
- pl[index].visible=1;
- pl[index].clipped=0;
- }
- }
-
- /***************************************************
- ** converte le coordinate nel mondo dell'oggetto **
- ** corrente nelle coordinate della camera **
- ***************************************************
- *** INPUT : *
- * in -> valore > 0 restituito da display3d. *
- *** OUTPUT: *
- * nessuno. *
- ***************************************************/
- void worldtocamera(in)
- struct ambient3d *in;
- {
- struct objectnode *obj;
- long int index,temp,tempx,tempy,tempz,active_axes;
- struct vertex *vc;
- struct matrix4x4 gv,*g_v;
- struct dir3d *vang;
-
- obj=pobj(in);
- vc=obj->vcamera;
- vang=&in->view_angle;
- g_v=&in->global_view;
-
- active_axes=0;
-
- if (vang->angx!=NULL) active_axes=active_axes+1;
- if (vang->angy!=NULL) active_axes=active_axes+2;
- if (vang->angz!=NULL) active_axes=active_axes+4;
-
- switch (active_axes)
- {
- case (0):
- for (index=0; index<obj->numverts; index++)
- {
- vc[index].x=vc[index].x+g_v->r3c0;
- vc[index].y=vc[index].y+g_v->r3c1;
- vc[index].z=vc[index].z+g_v->r3c2;
- }
- break;
- case (1):
- for (index=0; index<obj->numverts; index++)
- {
- vc[index].x=vc[index].x+g_v->r3c0;
- tempy=vc[index].y*g_v->r1c1+vc[index].z*g_v->r2c1;
- tempz=vc[index].y*g_v->r1c2+vc[index].z*g_v->r2c2;
- vc[index].z=(tempz >> SFIXV)+g_v->r3c2;
- vc[index].y=(tempy >> SFIXV)+g_v->r3c1;
- }
- break;
-
- case (2):
- for (index=0; index<obj->numverts; index++)
- {
- tempx=vc[index].x*g_v->r0c0+vc[index].z*g_v->r2c0;
- vc[index].y=vc[index].y+g_v->r3c1;
- tempz=vc[index].x*g_v->r0c2+vc[index].z*g_v->r2c2;
- vc[index].z=(tempz >> SFIXV)+g_v->r3c2;
- vc[index].x=(tempx >> SFIXV)+g_v->r3c0;
- }
- break;
-
- case (4):
- for (index=0; index<obj->numverts; index++)
- {
- tempx=vc[index].x*g_v->r0c0+vc[index].y*g_v->r1c0;
- tempy=vc[index].x*g_v->r0c1+vc[index].y*g_v->r1c1;
- vc[index].y=(tempy >> SFIXV)+g_v->r3c1;
- vc[index].x=(tempx >> SFIXV)+g_v->r3c0;
- vc[index].z=vc[index].z+g_v->r3c2;
- }
- break;
-
- default :
- for (index=0; index<obj->numverts; index++)
- {
- tempx=vc[index].x*g_v->r0c0+vc[index].y*g_v->r1c0+
- vc[index].z*g_v->r2c0;
- tempy=vc[index].x*g_v->r0c1+vc[index].y*g_v->r1c1+
- vc[index].z*g_v->r2c1;
- tempz=vc[index].x*g_v->r0c2+vc[index].y*g_v->r1c2+
- vc[index].z*g_v->r2c2;
- vc[index].x=(tempx >> SFIXV)+g_v->r3c0;
- vc[index].y=(tempy >> SFIXV)+g_v->r3c1;
- vc[index].z=(tempz >> SFIXV)+g_v->r3c2;
- }
- }
- }
-
- /******************************************************/
- /** rimuove le facce posteriori dell'oggetto corrente**/
- /** e calcola il flat shading dell'oggetto **/
- /******************************************************/
- void removebackfacesandshade(in)
- struct ambient3d *in;
- {
- struct objectnode *obj;
- struct vector *vp, *ls;
- struct vertex *v0,*v1,*v2;
- struct polygon *pol;
- long int x,ms1,ms,al,sha_org,shading,curr_poly,dp,intensity;
- struct vector u,v;
- struct vector normal,norm,sight;
- long int norml;
-
- vp=&in->view_point;
- ls=&in->light_source;
- obj=pobj(in);
- shading=obj->shade;
- sha_org=shading;
-
- x=ls->x;
-
- ms=in->maxintensity;
- ms1=ms << SFIXV;
- al=in->ambient_light >> SFIXV;
- for (curr_poly=0; curr_poly<obj->numpolys; curr_poly++)
- {
- shading=sha_org;
- pol=&obj->polys[curr_poly];
- if (pol->twosided==NULL AND pol->numpoints>2)
- {
- v0=&obj->vcamera[pol->vertexlist0];
- v1=&obj->vcamera[pol->vertexlist1];
- v2=&obj->vcamera[pol->vertexlist2];
-
- normalpol(v0,v1,v2,&normal);
-
- sight.x=vp->x - v0->x;
- sight.y=vp->y - v0->y;
- sight.z=vp->z - v0->z;
-
- dp=dotproduct(&normal,&sight);
- if (dp>=NULL)
- /* poligono ad una faccia */
- {
- pol->visible=1;
- switch(shading)
- {
- case(FLAT):
- /* calcolo lunghezza normale poligono */
- dp=dotproduct(&normal,ls);
- if (dp>NULL)
- {
- v0=&obj->vlocal[pol->vertexlist0];
- v1=&obj->vlocal[pol->vertexlist1];
- v2=&obj->vlocal[pol->vertexlist2];
- normalpol(v0,v1,v2,&normal);
-
- norml=vectormag3d(&normal);
- if (norml==NULL) norml=FIXV;
- intensity=al+(ms1*dp)/norml;
- if (intensity>ms) intensity=ms;
- /* intensity e' compreso ora tra 0 e ms ,si usera' questo valore */
- /* per trovare l'indice di sfumatura */
- pol->shade=pol->color+intensity;
- }
- else
- {
- pol->shade=pol->color+al;
- }
- break;
-
- case(SOLID):
- pol->shade=pol->color + (ms>>1);
- break;
-
- default:
- /* se tipo di shading <> da flat si assume solid */
- pol->shade=pol->color;
- }
- }
- else
- {
- pol->visible=0;
- }
- }
- else if (pol->numpoints>2)
- {
- /* poligono a due facce */
- pol->visible=1;
- if (pol->numpoints<3) shading=SOLID;
- switch (shading)
- {
- case(FLAT):
- v0=&obj->vcamera[pol->vertexlist0];
- v1=&obj->vcamera[pol->vertexlist1];
- v2=&obj->vcamera[pol->vertexlist2];
-
- normalpol(v0,v1,v2,&normal);
-
- dp=dotproduct(&normal,ls);
- if (dp>NULL)
- {
- /* calcolo lunghezza normale poligono */
- v0=&obj->vlocal[pol->vertexlist0];
- v1=&obj->vlocal[pol->vertexlist1];
- v2=&obj->vlocal[pol->vertexlist2];
- normalpol(v0,v1,v2,&normal);
-
- norml=vectormag3d(&normal);
- if (norml==NULL) norml=FIXV;
- intensity=al+(ms1*dp)/norml;
- if (intensity>ms) intensity=ms;
- pol->shade=pol->color+intensity;
- }
- else
- {
- pol->shade=pol->color+al;
- }
- break;
-
- case(SOLID):
- pol->shade=pol->color + (ms>>1) ;
- break;
-
- default:
- /* se tipo di shading <> da flat si assume solid */
- pol->shade=pol->color ;
- }
- }
- else
- {
- pol->visible=1;
- pol->shade=pol->color + (ms>>1) ;
- }
- }
-
- }
-
- /****************************************************/
- /** clippa le coordinate della camera dell'oggetto **/
- /** corrente rispetto al volume della visuale **/
- /****************************************************/
- void clipobject3d(in)
- struct ambient3d *in;
- {
- long int n_z, f_z, curr_poly;
- long int x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4;
- long int x1_cmp, y1_cmp, x2_cmp, y2_cmp, x3_cmp, y3_cmp, x4_cmp, y4_cmp;
- long int vert0, vert1, vert2, vert3, fov_width, fov_height;
- struct objectnode *obj;
- struct vertex *vc;
- struct polygon *pol;
-
- obj=pobj(in);
-
- vc=obj->vcamera;
- pol=obj->polys;
-
- /* converto in fixpoint */
- n_z=in->near_z*FIXV;
- f_z=in->far_z*FIXV;
-
- if (in->clip_mode==ZPLANE)
- {
- /* cerca di clippare ogni poligono con il volume della visuale */
- for (curr_poly=0 ;curr_poly<obj->numpolys ;curr_poly++)
- {
- /* test di quanti lati */
- switch(pol[curr_poly].numpoints)
- {
- case(1):
- z1=vc[pol[curr_poly].vertexlist0].z;
- z2=z1;
- z3=z1;
- z4=z4;
- break;
-
- case(2):
- z1=vc[pol[curr_poly].vertexlist0].z;
- z2=vc[pol[curr_poly].vertexlist1].z;
- z3=z2;
- z4=z2;
- break;
-
- case(3):
- z1=vc[pol[curr_poly].vertexlist0].z;
- z2=vc[pol[curr_poly].vertexlist1].z;
- z3=vc[pol[curr_poly].vertexlist2].z;
- z4=z3;
- break;
-
- case(4):
- z1=vc[pol[curr_poly].vertexlist0].z;
- z2=vc[pol[curr_poly].vertexlist1].z;
- z3=vc[pol[curr_poly].vertexlist2].z;
- z4=vc[pol[curr_poly].vertexlist3].z;
- break;
- }
-
- if ((z1<n_z AND z2<n_z AND z3<n_z AND z4<n_z) OR
- (z1>f_z AND z2>f_z AND z3>f_z AND z4>f_z))
- pol[curr_poly].clipped=1;
- }
- }
- else
- {
- /* FRUSTUM MODE CLIP */
- /* calcolo i campi visivi in fixpoint */
- fov_width=(in->half_screen_width*FIXV)/in->viewing_distance;
- fov_height=((in->half_screen_height*in->inv_aspect_ratio) /
- in->viewing_distance);
- for (curr_poly=0 ;curr_poly<obj->numpolys ;curr_poly++)
- {
-
- /* test di quanti lati */
- switch(pol[curr_poly].numpoints)
- {
- case(1):
- vert0=pol[curr_poly].vertexlist0;
- x1=vc[vert0].x;
- y1=vc[vert0].y;
- z1=vc[vert0].z;
- x2=x1;
- y2=y1;
- z2=z1;
- x3=x1;
- y3=y1;
- z3=z1;
- x4=x1;
- y4=y1;
- z4=z1;
- break;
- case(2):
- vert0=pol[curr_poly].vertexlist0;
- vert1=pol[curr_poly].vertexlist1;
- x1=vc[vert0].x;
- y1=vc[vert0].y;
- z1=vc[vert0].z;
- x2=vc[vert1].x;
- y2=vc[vert1].y;
- z2=vc[vert1].z;
- x3=x2;
- y3=y2;
- z3=z2;
- x4=x2;
- y4=y2;
- z4=z2;
- break;
- case(3):
- vert0=pol[curr_poly].vertexlist0;
- vert1=pol[curr_poly].vertexlist1;
- vert2=pol[curr_poly].vertexlist2;
- x1=vc[vert0].x;
- y1=vc[vert0].y;
- z1=vc[vert0].z;
- x2=vc[vert1].x;
- y2=vc[vert1].y;
- z2=vc[vert1].z;
- x3=vc[vert2].x;
- y3=vc[vert2].y;
- z3=vc[vert2].z;
- x4=x3;
- y4=y3;
- z4=z3;
- break;
- case(4):
- vert0=pol[curr_poly].vertexlist0;
- vert1=pol[curr_poly].vertexlist1;
- vert2=pol[curr_poly].vertexlist2;
- vert3=pol[curr_poly].vertexlist3;
- x1=vc[vert0].x;
- y1=vc[vert0].y;
- z1=vc[vert0].z;
- x2=vc[vert1].x;
- y2=vc[vert1].y;
- z2=vc[vert1].z;
- x3=vc[vert2].x;
- y3=vc[vert2].y;
- z3=vc[vert2].z;
- x4=vc[vert3].x;
- y4=vc[vert3].y;
- z4=vc[vert3].z;
- break;
- }
- if (z1<n_z AND z2<n_z AND z3<n_z AND z4<n_z)
- {
- pol[curr_poly].clipped=1;
- continue;
- }
- if (z1>f_z AND z2>f_z AND z3>f_z AND z4>f_z)
- {
- pol[curr_poly].clipped=1;
- continue;
- }
-
- x1_cmp=(fov_width*z1) >> SFIXV;
- x2_cmp=(fov_width*z2) >> SFIXV;
- x3_cmp=(fov_width*z3) >> SFIXV;
- x4_cmp=(fov_width*z4) >> SFIXV;
-
- if (!((x1>-x1_cmp OR x2>-x2_cmp OR x3>-x3_cmp OR x4>-x4_cmp)
- AND (x1<x1_cmp OR x2<x2_cmp OR x3<x3_cmp OR x4<x4_cmp)))
- {
- pol[curr_poly].clipped=1;
- continue;
- }
- y1_cmp=(fov_height*z1) >> SFIXV;
- y2_cmp=(fov_height*z2) >> SFIXV;
- y3_cmp=(fov_height*z3) >> SFIXV;
- y4_cmp=(fov_height*z4) >> SFIXV;
-
- if (!((y1>-y1_cmp OR y2>-y2_cmp OR y3>-y3_cmp OR y4>-y4_cmp)
- AND (y1<y1_cmp OR y2<y2_cmp OR y3<y3_cmp OR y4<y4_cmp)))
- {
- pol[curr_poly].clipped=1;
- continue;
- }
- }
- }
- }
-
- /******************************************************/
- /** crea la lista di tutti i poligoni visibili nella **/
- /** frame corrente e li memorizza gia' proiettati **/
- /** e' gia' stato ottimizzato il piu' possibile. **/
- /** Ora si calcola la distanza tra il punto medio del**/
- /** poligono e l'osservatore per il succ. riordino. **/
- /******************************************************/
- void generatepolylist(in)
- struct ambient3d *in;
- {
- long int *iwp;
- long int zx,zy,zxp,zyp,id,fix1,fix,curr_poly,i,ii,mz,mx,my,x,y,z;
- struct pixel *pt;
- struct objectnode *obj;
- struct vertex *vc;
- struct polygon *pol;
- struct polytemp *wpl;
-
- #ifdef DEBUG
- char dbg[100];
- #endif
-
- iwp=in->iwpolys;
- pt=(struct pixel *)in->temp;
-
- #ifdef DEBUG
- sprintf(dbg,"pt=%ld\n",pt);
- write_dbg(dbg);
- #endif
-
- obj=resetobj(in);
- id=0;
- curr_poly=0;
- fix=(in->aspect_ratio*in->viewing_distance) >> SFIXV;
- fix1=in->aspect_ratio;
- zy=(fix*in->zoom) >> SFIXV;
- zx=(in->viewing_distance*in->zoom) >> SFIXV;
- zxp=in->zoom;
- zyp=(in->aspect_ratio*in->zoom) >> SFIXV;
-
- /*
- #ifdef DEBUG
- sprintf(dbg,"\n--- ciclo generatepolylist ---\n");
- write_dbg(dbg);
- sprintf(dbg,"view distance=%ld fix=%ld\n",in->viewing_distance,fix);
- write_dbg(dbg);
- #endif
- */
-
- do
- {
- if (obj->clipped==0 AND obj->state!=0)
- {
- /** proietto tutti i punti dell'oggetto corrente **/
- switch(in->projection_type)
- {
- case(PROSP_P) :
- /* uso proiezione prospettica */
- for(i=0 ;i<obj->numverts ;i++ )
- {
- vc=&obj->vcamera[i];
- z=vc->z;
- if (z==NULL) z=FIXV;
- pt[i].x=in->half_screen_width +
- (vc->x*zx)/z;
- pt[i].y=in->half_screen_height -
- (vc->y*zy)/z;
-
- /*
- #ifdef DEBUG
- sprintf(dbg,"vertice #%ld\nxp=%ld yp=%ld \n",i,pt[i].x,pt[i].y);
- write_dbg(dbg);
- sprintf(dbg,"x=%ld y=%ld z=%ld\n",vc->x,vc->y,z);
- write_dbg(dbg);
- #endif
- */
-
- }
- break;
- case(PARAL_P) :
- /* uso proiezione parallela */
- for(i=0 ;i<obj->numverts ;i++ )
- {
- vc=&obj->vcamera[i];
- pt[i].x=in->half_screen_width +
- ((vc->x*zxp) >> (2*SFIXV));
- pt[i].y=in->half_screen_height +
- ((vc->y*zyp) >> (2*SFIXV));
- }
- break;
- }
- /* genero lista di poligoni gia' proiettati */
- vc=obj->vcamera;
- for(curr_poly=0 ;curr_poly<obj->numpolys ;curr_poly++)
- {
- pol=&obj->polys[curr_poly];
- if (pol->visible!=NULL AND pol->clipped==NULL)
- {
- /* reinizializzo puntatore a indice su lista poligoni */
- /* per velocizzare il successivo riordino */
- wpl=&in->worldpolys[id];
- iwp[id++]=(long int )wpl;
- mx=0;
- my=0;
- mz=0;
- wpl->numpoints=pol->numpoints;
- wpl->shade=pol->shade;
- wpl->vmode=obj->shade;
- wpl->obj=obj->id;
- wpl->npol=curr_poly;
-
- i=pol->vertexlist0;
- wpl->x1=pt[i].x;
- wpl->y1=pt[i].y;
- mx=mx+vc[i].x;
- my=my+vc[i].y;
- mz=mz+vc[i].z;
-
- if (pol->numpoints>=2)
- {
- i=pol->vertexlist1;
- wpl->x2=pt[i].x;
- wpl->y2=pt[i].y;
- mx=mx+vc[i].x;
- my=my+vc[i].y;
- mz=mz+vc[i].z;
- }
-
- if (pol->numpoints>=3)
- {
- i=pol->vertexlist2;
- wpl->x3=pt[i].x;
- wpl->y3=pt[i].y;
- mx=mx+vc[i].x;
- my=my+vc[i].y;
- mz=mz+vc[i].z;
-
- wpl->x4=wpl->x1;
- wpl->y4=wpl->y1;
- }
-
- if (pol->numpoints==4)
- {
- i=pol->vertexlist3;
- wpl->x4=pt[i].x;
- wpl->y4=pt[i].y;
- mx=mx+vc[i].x;
- my=my+vc[i].y;
- mz=mz+vc[i].z;
-
- wpl->x5=wpl->x1;
- wpl->y5=wpl->y1;
- }
- /* calcolo ora il punto medio */
- ii=pol->numpoints << SFIXV;
- mx=mx/ii ;
- my=my/ii ;
- mz=mz/ii ;
- /*
- ora calcolo la distanza, considerando che l'osservatore ora
- e' nell'origine
- (non calcolo la radice quadrata, poiche' altrimenti aumento l'errore
- e il tempo di calcolo).
- */
-
- wpl->svalue=mx*mx + my*my + mz*mz;
- /*
- #ifdef DEBUG
- sprintf(dbg,"dist=%ld\n",wpl->svalue);
- write_dbg(dbg);
- #endif
- */
- }
- }
- }
- obj=nextobj(in);
- }while(obj!=NULL);
-
- in->total_polys=id;
-
- /********************/
- }
-
- /**********************************************
- ** riporto oggetto attuale sul primo e **
- ** resituisco puntatore a oggetto. **
- **********************************************
- *** INPUT : *
- * in -> valore > 0 restituito da display3d. *
- *** OUTPUT: *
- * puntatore a struttura 1# oggetto. *
- **********************************************/
- struct objectnode *resetobj(in)
- struct ambient3d *in;
- {
-
- in->attuale=0;
-
- return (pobj(in));
- }
-
- /**********************************************
- ** sposto oggetto attuale su prossimo se **
- ** finiti restituisco 0 altrimenti puntore **
- ** a oggetto. **
- **********************************************
- *** INPUT : *
- * in -> valore > 0 restituito da display3d. *
- *** OUTPUT: *
- * >0 - puntatore a oggetto successivo. *
- * =0 - oggetti finiti. *
- **********************************************/
- struct objectnode *nextobj(in)
- struct ambient3d *in;
- {
-
- if (in->attuale==in->total_objects-1) return(0);
-
- in->attuale=in->attuale+1;
-
- return (pobj(in));
- }
-
- /*******************************************
- ** restituisce indirizzo oggetto attuale **
- *******************************************/
-
- struct objectnode *pobj(in)
- struct ambient3d *in;
- {
-
- return(&in->objects[in->attuale]);
-
- }
-
- /************************************************
- ** aggiorna tutti i valori precalcolati sul **
- ** oggetto corrente. **
- ************************************************
- *** INPUT : *
- * in -> valore > 0 restituito da display3d. *
- *** OUTPUT: *
- * nessuno. *
- ************************************************/
- void aggobj(in)
- struct ambient3d *in;
- {
-
- computeobjectbox(in);
-
- }
-
- /**********************************************/
- /** calcola il bounding box dell'oggetto at- **/
- /** tuale per il controllo delle collisioni **/
- /**********************************************/
- void computeobjectbox(in)
- struct ambient3d *in;
- {
- struct objectnode *ob;
- struct vertex *vt;
- long int xmax,ymax,zmax,xmin,ymin,zmin;
- long int x,y,z,i;
-
- ob=pobj(in);
-
- vt=ob->vlocal;
-
- xmax=vt[0].x;
- ymax=vt[0].y;
- zmax=vt[0].z;
- xmin=vt[0].x;
- ymin=vt[0].y;
- zmin=vt[0].z;
-
- for(i=1 ;i<ob->numverts ; i++)
- {
- x=vt[i].x;
- y=vt[i].y;
- z=vt[i].z;
- if (x>xmax) xmax=x;
- if (x<xmin) xmin=x;
- if (y>ymax) ymax=y;
- if (y<ymin) ymin=y;
- if (z>zmax) zmax=z;
- if (z<zmin) zmin=z;
- }
-
- ob->xmax=xmax;
- ob->ymax=ymax;
- ob->zmax=zmax;
- ob->xmin=xmin;
- ob->ymin=ymin;
- ob->zmin=zmin;
-
- }
-
- /************************************
- ** routin richiamata da quicksort **
- ** occhio e' recursiva. **
- ** I parametri non possono percio'**
- ** essere passati tramite registri**
- ************************************/
- void qsort(lo0,hi0,pol,count)
- long int lo0;
- long int hi0;
- long int *pol;
- long int *count;
- {
- long int it, lo, hi, mid, t;
- struct polytemp *wpl;
-
- lo=lo0;
- hi=hi0;
- it=count[0];
-
- if (hi0>lo0)
- /* stabilisco arbitrariamente il pivot point nel mezzo dell'array */
- {
- wpl=(struct polytemp *)pol[(lo0+hi0)>>1];
- mid=wpl->svalue;
-
- /* eseguo il loop finche non incrocio indici */
- while(lo<=hi)
- /* trovo il primo elemento minore o uguale a mid partendo da sinistra */
- {
- wpl=(struct polytemp *)pol[lo];
- while(lo<hi0 AND wpl->svalue>mid)
- {
- lo++;
- wpl=(struct polytemp *)pol[lo];
- it++;
- }
- /* trovo il primo elemento maggiore o uguale a mid partendo da destra */
- wpl=(struct polytemp *)pol[hi];
- while(hi>lo0 AND wpl->svalue<mid)
- {
- hi--;
- wpl=(struct polytemp *)pol[hi];
- it++;
- }
- /* se gli indici non si sono incrociati scambio elementi */
- if (lo<=hi)
- {
- t=pol[hi];
- pol[hi]=pol[lo];
- pol[lo]=t;
- lo++;
- hi--;
- }
- }
- }
-
- count[0]=it;
-
- if (lo0<hi) qsort(lo0,hi,pol,count);
-
- if (lo<hi0) qsort(lo,hi0,pol,count);
-
- }
-
- /******************************************************
- ** visualizza un gruppo di poligoni nella rastport **
- ** corrente(purche di 3 o 4 lati). **
- ** E' ottimizzata il piu' possibile. **
- ******************************************************
- **** INPUT : **
- ** amb ->valore non 0 ritornato da GD_display3d(). **
- ** iwp ->puntatore ad array di puntatori a strut- **
- ** ture polytemp. **
- ** total_polys ->n# totale elementi nell'array iwp **
- ** colb ->se >=0 allora poligoni con bordo di quel **
- ** colore. **
- **** OUTPUT: **
- ** nessuno. **
- ******************************************************/
- void paintpol(amb,iwp,total_polys,colb)
- struct ambient3d *amb;
- long int *iwp;
- long int total_polys;
- long int colb;
- {
- struct grafica *graf;
- struct RastPort *rast;
- struct polytemp *wpl;
- long int i,f,f1;
- long int ob,m1,mx;
- short int *pvert;
-
- #ifdef DEBUG
- char dbg[100];
- #endif
-
- graf=amb->graf;
-
- rast=graf->rast;
- mx=graf->lb_af;
-
- #ifdef DEBUG
- sprintf(dbg,"ambient3d=%ld rast=%ld\n",amb,rast);
- write_dbg(dbg);
- #endif
-
- f1=((struct polytemp *)iwp[0])->shade;
- SetAPen(rast,f1);
- m1=NULL;
- ob=((struct polytemp *)iwp[0])->obj;
- for (i=0;i<total_polys;i++)
- {
- wpl=(struct polytemp *)iwp[i];
- pvert=(short int *)wpl;
- /* visualizzo il poligono */
- /** visualizza un poligono proiettato **/
- f=wpl->shade;
- if (f1!=f)
- {
- /*
- SetAPen(rast,f);
- */
- f1=f;
- }
- switch(wpl->numpoints)
- {
- case (1) :
- /* 1 vertice -> disegno un punto */
- pixel(amb,pvert[0],pvert[1],f);
- break;
- case (2) :
- /* 2 vertici -> disegno una linea */
- line(amb,pvert[0],pvert[1],pvert[2],pvert[3],f);
- break;
- case (3) :
- /* 3 vertici -> poligono triangolare disegno in base a wpl->vmode */
- if (wpl->vmode!=WIREF)
- {
- drw_t(amb,pvert,f1,colb);
- }
- else
- {
- line(amb,pvert[0],pvert[1],pvert[2],pvert[3],f1);
- line(amb,pvert[2],pvert[3],pvert[4],pvert[5],f1);
- line(amb,pvert[4],pvert[5],pvert[0],pvert[1],f1);
- }
- break;
- case (4) :
- /* 4 vertici -> poligono quadrangolare disegno in base a wpl->vmode*/
- if (wpl->vmode!=WIREF)
- {
- drw_q(amb,pvert,f1,colb);
- }
- else
- {
- line(amb,pvert[0],pvert[1],pvert[2],pvert[3],f1);
- line(amb,pvert[2],pvert[3],pvert[4],pvert[5],f1);
- line(amb,pvert[4],pvert[5],pvert[6],pvert[7],f1);
- line(amb,pvert[6],pvert[7],pvert[0],pvert[1],f1);
- }
- break;
- }
- }
-
- }
-
- /**********************************************
- ** effettuo ordinamento poligoni proiettati **
- ** via quicksort **
- ** mediamente 4 volte piu' veloce dello **
- ** shellsort. **
- **********************************************
- **** INPUT : **
- ** len -> numero di poligoni da riordinare **
- ** pol -> array di puntatori alle strutture **
- ** polytemp, da riordinare. **
- **** OUTPUT: **
- ** n# di passi effettuati per l'ordinamento.**
- **********************************************/
- long int quicksort(len,pol)
- long int len;
- long int *pol;
- {
- long int itera;
-
- itera=0;
-
- if (len>NULL) qsort(0,len-1,pol,&itera);
-
- return(itera);
- }
- /*******************************************************************/
-